#define __USE_BSD
#define __FAVOR_BSD
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <pcap.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <netinet/ip_icmp.h>

#define MAXBYTES2CAPTURE 2048

// 打印IP地址的辅助函数
void print_ip_address(u_char *ip) {
    printf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
}

int main(int argc, char *argv[]) {
    bpf_u_int32 netaddr = 0, mask = 0;
    int count = 0, i = 0;
    struct bpf_program filter;
    char errbuf[PCAP_ERRBUF_SIZE];
    memset(errbuf, 0, PCAP_ERRBUF_SIZE);
    struct ip *iphdr = NULL;
    pcap_t *descr = NULL;
    struct pcap_pkthdr pkthdr;
    struct tcphdr *tcphdr = NULL;
    const unsigned char *packet = NULL;

    if (argc != 2) {
        fprintf(stderr, "USAGE: ftpgrabber <interface>\n");
        exit(1);
    }

    descr = pcap_open_live(argv[1], MAXBYTES2CAPTURE, 1, 512, errbuf);
    if (descr == NULL) {
        fprintf(stderr, "pcap_open_live(): %s \n", errbuf);
        exit(1);
    }

    if (pcap_lookupnet(argv[1], &netaddr, &mask, errbuf) == -1) {
        fprintf(stderr, "ERROR: pcap_lookupnet(): %s\n", errbuf);
        exit(1);
    }

    // 修改过滤条件，捕获ICMP报文
    if (pcap_compile(descr, &filter, "icmp", 1, mask) == -1) {
        fprintf(stderr, "Error in pcap_compile(): %s\n", pcap_geterr(descr));
        exit(1);
    }

    if (pcap_setfilter(descr, &filter) == -1) {
        fprintf(stderr, "Error in pcap_setfilter(): %s\n", pcap_geterr(descr));
        exit(1);
    }

    while (1) {
        if ((packet = pcap_next(descr, &pkthdr)) == NULL) {
            fprintf(stderr, "Error in pcap_next()\n", errbuf);
            exit(1);
        }

        iphdr = (struct ip *)(packet + 14);
        // 检查协议类型是否为ICMP
        if (iphdr->ip_p == IPPROTO_ICMP) {
            struct icmphdr *icmphdr = (struct icmphdr *)(packet + 14 + (iphdr->ip_hl << 2));
            // 检查是否为ICMP ECHO请求
            if (icmphdr->type == ICMP_ECHO) {
                if (count == 0)
                    printf("-> Received ICMP ECHO Request Packet No.%d:\n", ++count);
                printf(" Protocol Type: ICMP\n");
                printf(" SRC IP: ");
                print_ip_address((u_char *)&iphdr->ip_src);
                printf("\n");
                printf(" DST IP: ");
                print_ip_address((u_char *)&iphdr->ip_dst);
                printf("\n");
                printf(" PACKET PAYLOAD:\n ");
                for (i = 0; i < pkthdr.len; i++) {
                    if (isprint(packet[i]))
                        printf("%c ", packet[i]);
                    else
                        printf(". ");
                    if ((i % 16 == 0 && i != 0) || i == pkthdr.len - 1)
                        printf("\n ");
                }
                printf("\n");
            }
        }
    }

    return 0;
}